home *** CD-ROM | disk | FTP | other *** search
/ Scene 96 / Scene 96 International Edition (Zyklop Software) (Disc 2) (1997).iso / misc / coding / vgacodng / part03.txt < prev    next >
Text File  |  1996-08-07  |  14KB  |  333 lines

  1.  
  2.                              VGA-Kurs - Part #3
  3.  
  4. "T.C.P.'s Beginner's Guide To VGA Coding"(TM) ist wieder da mit Teil III!
  5. Zu Beginn als Appetithäppchen eine erneut schnellere PutPixel-Routine. Die ist
  6. jetzt meiner Meinung nach nicht schneller zu machen (höchstens in 386er Code).
  7. Wer anderer Meinung ist, soll seine Lösung hier präsentieren.
  8. Wichtig bei dieser Prozedur ist, das stets ein GLOBALE Konstante
  9. 'VGA : word = $A000;' deklariert wird.
  10.  
  11. const VGA : word = $A000;
  12. procedure PutPixel(x,y:word;c:byte);assembler;
  13. asm
  14.   mov     es,VGA
  15.   mov     di,x
  16.   mov     dx,y
  17.   mov     bx,dx
  18.   shl     dx,8
  19.   shl     bx,6
  20.   add     dx,bx
  21.   add     di,dx
  22.   mov     al,c
  23.   stosb
  24. end;
  25.  
  26. Außerdem noch unentbehrlich: Eine GetPixel-Funktion. Diese ermittelt den
  27. Farbwert des Pixels, der an den angegebenen Koordinaten steht.
  28.  
  29. function GetPixel(x,y:word) : byte;assembler;
  30. asm
  31.   mov     es,vga
  32.   mov     di,x
  33.   mov     dx,y
  34.   mov     bx,dx
  35.   shl     dx,8
  36.   shl     bx,6
  37.   add     dx,bx
  38.   add     di,dx
  39.   mov     al,es:[di]
  40.   mov     [bp-1],al
  41. end;
  42.  
  43. Diese Funktion verfährt bei der Berechnung des Offsets des Pixels haargenau
  44. so wie die Schwester-Prozedur. Nur am Schluß gibt es eine kleine Änderung.
  45. Statt den Pixel zu schreiben wird der Farbwert, der bekanntlich an der
  46. Adresse A000h:Y*320+X steht, in AL ausgelesen und dann als Funktionsergebnis
  47. zurückgeliefert.
  48. Nun wäre es vielleicht an der Zeit, daß sich der geneigte Leser eine Unit
  49. mit den besprochenen Routinen zusammenstellt, um die Beispiele einfacher
  50. kompilieren zu können und eigene Programme schneller zu erstellen.
  51. Aber nun zur Sache: In dieser Ausgabe werden wir uns einem häufig besprochenen
  52. und geheimnisumwitterten Thema widmen: Dem Scrolly.
  53. Was ein Scrolly ist, weiß wahrscheinlich jeder. Eine Zeichenkette wird zum
  54. angenehmeren Lesen von rechts nach links ge(sc)rollt. Dabei wird zuerst ein
  55. Teil der Laufschrift am rechten Rand des Screens gezeigt, dann ein Stück nach
  56. links bewegt und schließlich der nächste Teil angefügt. Einfaches Prinzip,
  57. große Wirkung. Um wirklich zu beeindrucken, sollte der Scrolly aber nicht nur
  58. einfach scrollen sondern z.B. noch ein Plasma im Hintergrund bewegt werden
  59. oder Ähnliches.
  60. Beginnen wir im Praxisteil mit einem einfachen Textmode-Scrolly. Der Text wird
  61. in der Konstanten Text abgelegt. Nun wird innerhalb der Schleife zuerst der
  62. Buchstabe des Textes auf den Screen geschrieben (Zeile 13), dessen Nummer in
  63. der Variablen Charno steht. Nun wird die komplette Zeile ab dem 2. Zeichen um
  64. 1 Zeichen nach links verschoben. Dazu folgendes: Wir haben in der ersten
  65. Ausgabe gelernt wie der Bildschirmspeicher ab Adresse A000h organisiert ist.
  66. Zur Erinnerung: Die Pixelinformationen sind hintereinander in einem 64000 Byte
  67. großen Bereich abgelegt. Die Offset-Adresse läßt sich nach der Formel
  68. Offset = Y-Koord * 320 + X-Koord berechnen. Nun, im Textmodus ist dies so
  69. ähnlich. Der Bildschirmspeicher liegt an der Adresse B800h (B000h bei
  70. Hercules), und ist 4000 Byte groß. Bei Segment B800, Offset 0 liegt also der
  71. ASCII-Code des ersten Zeichens auf dem Bildschirm. Steht nun auf dem Screen
  72. bei den Koords (0,0) ein "A", so findet man bei Adresse $B800:0 den Wert 65,
  73. also den ASCII-Code von "A". An Adresse $B800:1 liegt nun aber nicht, wie zu
  74. vermuten wäre, der ASCII-Code des zweiten Zeichens, Koords (1,0), sondern das
  75. sog. Attributbyte des ersten Zeichens. Dieses beeinhaltet die Farbe und die
  76. Art des Zeichens, z.B. rot und blinkend. Um nun dem "A" die Farbe Rot und das
  77. Attribut "blinkend" zuzuweisen, rechnet man den Wert für die Farbe Rot (4) und
  78. für "blinkend" (128) zusammen, erhält 132, und schreibt diesen Wert an die
  79. Adresse $B800:1. Unter Pascal kann man zum Ändern von Textfarbe und Attribut
  80. auch die Prozedur "Textcolor" der Unit Crt benutzen. Rot und blinkend stellt
  81. man z.B. ein mit "Textcolor(red+blink);".
  82. Die Formel zum Berechnen der Adresse eines Zeichens ist also:
  83. Adresse = (Y-Koord * 80 + X-Koord) * 2.
  84. Zurück zu unserem Scrolly. Mit der Standard-Prozedur "Move" werden nun ab der
  85. Adresse $B800:1922 158 Bytes (79 Zeichen) nach $B800:1920 (also um ein Zeichen
  86. nach links) kopiert. Nun wird nur noch die Nummer des aktuellen Buchstabens
  87. erhöht und überprüft, ob die Zeichenkette bereits am Ende ist, und wenn ja
  88. wird Charno wieder auf 1 gesetzt. Dies geht solange weiter, bis eine Taste
  89. gedrückt wird.
  90. Achso: Generell ist es bei Scrollies natürlich wichtig, auf ein entsprechend
  91. flüssiges Scrolling zu achten. Dies besorgt die Prozedur "WaitRetrace", die
  92. wir schon in der letzten Ausgabe kennengelernt haben. Ihr könnt das
  93. "Waitretrace" ja mal aus der Schleife entfernen und durch ein "Delay(10)"
  94. ersetzen, und zusehen, was für ein Geruckel dabei herauskommt.
  95. Augenbeleidigend!
  96.  
  97. program Scrolly1;
  98. uses crt;
  99. const Text : string = 'Hallo, dies ist ein Test Sc'+
  100.                       'rolly, der sich solange wie'+
  101.                       'derholt, bis ein Taste gedr'+
  102.                       'ückt wird..................';
  103. var Charno : byte;
  104.  
  105. procedure WaitRetrace;assembler;
  106. asm
  107.      mov     dx,3DAh
  108. @l1: in      al,dx
  109.      and     al,08h
  110.      jz      @l1
  111. @l2: in      al,dx
  112.      and     al,08h
  113.      jz      @l2
  114. end;
  115.  
  116. begin
  117.   Charno := 1;   { Erstes Zeichen des Scrolltextes }
  118.   clrscr;                     { Bildschirm löschen }
  119.   gotoxy(80,13); { Zum letzten Zeichen in Zeile 13 }
  120.   repeat
  121.     WaitRetrace;
  122.     write(Text[Charno]);       { Zeichen schreiben }
  123.     move(mem[$B800:1922],mem[$B800:1920],158);
  124.     { 79 Zeichen um 1 Zeichen nach links schieben }
  125.     inc(Charno);                { Nächstes Zeichen }
  126.     if Charno > length(Text) then Charno := 1;
  127.    { Wenn Zeichenkette am Ende, von vorne beginnen }
  128.     gotoxy(80,13);      { Wieder zum Ausgangspunkt }
  129.   until keypressed;
  130.   readkey;
  131. end.
  132.  
  133. Mal wieder eine Anmerkung: Der GotoXY-Befehl benutzt, wahrscheinlich um den
  134. Umgang mit der Prozedur für Anfänger zu erleichtern, ein Koordinatensystem,
  135. das bei (1,1) beginnt. Wenn ihr also zu (20,20) wollt, müßt ihr GotoXY(21,21)
  136. eingeben. Dies ist oft sehr verwirrend, und man kann leider nur Abhilfe
  137. schaffen, wenn man sich eine eigene GotoXY-Variante schreibt.
  138. So, das waren erstmal die Grundlagen. Aber was wir wollten, war ja ein Scrolly
  139. im VGA-Modus. Doch hier ist das Ganze nicht mehr so einfach. Als erstes
  140. benötigen wir einen Font, denn sonst haben wir ja nichts zum Scrollen. Ich
  141. gehe mal davon aus, daß keiner von euch gewillt ist, sich jetzt einen eigenen
  142. Font zu zeichnen, also müssen wir uns einen aus dem BIOS-Rom holen und so
  143. einrichten, daß wir frei auf ihn zugreifen können.
  144.  
  145. var FontSeg,FontOfs : word;
  146. procedure GetFont;assembler;
  147. asm
  148.   mov     ax,1130h
  149.   mov     bh,3          { Font-Nummer für 8x8-Font }
  150.   int     10h
  151.   mov     FontSeg,es
  152.   { Segment, in dem der Font abgelegt ist }
  153.   mov     FontOfs,bp
  154.   { Offset des Fonts }
  155. end;
  156.  
  157. Rufen wir diese Prozedur auf, haben wir an Adresse FontSeg:FontOfs den 8 mal 8
  158. Pixel-BIOS-Font. Ein Buchstabe ist also 8 Byte groß. Im ersten Byte stehen in
  159. den einzelnen Bits die Informationen der ersten Zeile des Buchstabens, im
  160. zweiten Byte die Bits der zweiten Reihe usw. Um nun festzustellen, ob im Font
  161. ein Pixel gesetzt (Bit=1) ist oder nicht (Bit=0), muß man die Bits mit den
  162. entsprechenden Potenzen von 2 und-verknüpfen.
  163. Im folgenden VGA-Modus-Scrolly wird also zuerst die erste Spalte des ersten
  164. Buchstabens angezeigt, auf den Retrace gewartet, dann die komplette Zeile um
  165. ein Pixel nach links verschoben und die nächste Spalte auf den Screen
  166. geschrieben.
  167. Die Nummer des Buchstabens steht wieder in Charno, die Spalte in Charpos.
  168. In Character wird der ASCII-Code des aktuellen Zeichens abgelegt.
  169.  
  170. program Scrolly2;
  171. uses crt;
  172. const VGA = $A000;
  173.       Bits : array[0..7] of byte =
  174.                (128,64,32,16,8,4,2,1);
  175.       Text : string = 'Ein Scrolly im VGA-Modus 13'+
  176.                       'h, er scrollt und scrollt u'+
  177.                       'nd scrollt.................';
  178. var FontSeg,FontOfs : word;
  179.  
  180. { Hier die Prozeduren GetFont und WaitRetrace
  181.   einsetzen }
  182.  
  183. procedure Scroll;
  184. var I,J : word;
  185.     CharPos,CharNo,Color,Character : byte;
  186. begin
  187.   CharNo := 1;                   { Anfangsposition }
  188.   repeat
  189.     Character := ord(Text[CharNo]);
  190.     { ASCII-Code holen }
  191.     for CharPos := 0 to 7 do begin  { 8x8 Pixel je }
  192.       for I := 0 to 7 do begin      { Zeichen      }
  193.         if mem[FontSeg:FontOfs+(Character*8)+I] and
  194.            Bits[CharPos] <> 0 then Color := 31
  195.         else Color := black;
  196.         { Wenn daß entsprechende Bit gesetzt ist,  }
  197.         { dann Farbe weiß (31) setzen, andernfalls }
  198.         { schwarz.                                 }
  199.         mem[$A000:((100+I)*320)+319] := Color;
  200.         { Pixel setzen }
  201.       end;
  202.       WaitRetrace;
  203.       for J := 0 to 7 do for I := 0 to 318 do
  204.         mem[$A000:((100+J)*320)+I] :=
  205.           mem[$A000:((100+J)*320)+1+I];
  206.       { Alles um einen Pixel nach links bewegen }
  207.     end;
  208.     inc(CharNo);
  209.     if CharNo > length(Text) then CharNo := 1;
  210.   until keypressed;
  211.   readkey;
  212. end;
  213.  
  214. begin
  215.   GetFont;
  216.   asm mov ax,13h; int 10h end;    { VGA-Modus 13h }
  217.   Scroll;
  218.   asm mov ax,03h; int 10h end;        { Textmodus }
  219. end.
  220.  
  221. Dieser Scrolly würde wahrscheinlich in einem Demo sehr wenig Anklang finden,
  222. da der Font nicht gerade zu den allerhübschesten zählt. Außerdem ist er bloß
  223. einfarbig. Letzteres Problem läßt sich allerdings sehr leicht aus der Welt
  224. schaffen.
  225. Deklariert einfach ein Array of byte mit den gewünschten Farben der Zeilen.
  226. Zum Beispiel:
  227.  
  228. const Colors : array[0..7] of byte = (25,27,29,31,31,29,27,25);
  229.  
  230. Nun ersetzt ihr im Listing die Zeile "Bits[CharPos] <> 0 then Color := 31"
  231. durch "Bits[CharPos] <> 0 then Color := Colors[I]". Dadurch wird jeder Zeile
  232. des Scrollies ein der Reihe nach der entsprechende Farbwert aus dem
  233. Colors-Array zugewiesen. In diesem Fall beeinhaltet das Array einen
  234. Grau-Verlauf. Übrigens stellen in der Standard-Palette (s. Teil II) die Farben
  235. Nummer 16 bis 31 einen Grau-Verlauf bereit (16=Schwarz, 31=Weiß), den man bei
  236. Bedarf nutzen sollte.
  237. Wer das Beispiel aufmerksam studiert hat, dem wird es auch nicht schwerfallen,
  238. einen eigenen Font einzubauen.
  239. So viel zu horizontalen Scrollies. Natürlich gibt es auch vertikale Scrollies
  240. (eines der besten Beispiele ist am Ende von 2nd Reality zu bestaunen).
  241. Diese sind im Modus 13h zwar ruckelfrei realisierbar, doch durch das Fehlen
  242. weiterer Bildschirmseiten (wie im Mode-X, s.u.) wird dies ein sinnloses
  243. Unterfangen, denn es kann maximal eine Seite gescrollt werden, dann ist das
  244. Ende der Fahnenstange erreicht.
  245. Hier jedoch trotzdem ein solcher Scrolly im Mode 13h, nur um das Prinzip zu
  246. verdeutlichen:
  247.  
  248. program VertScrolly;
  249. uses crt;
  250. const VGA : word = $A000;
  251. var i,j : word;
  252.     c   : char;
  253.  
  254. { Hier Prozedur WaitRetrace einfügen }
  255.  
  256. procedure SetStart(Adresse:word);assembler;
  257. asm
  258.   mov     dx,3D4h             { CRTC-Indexregister }
  259.   mov     al,0Ch
  260.   mov     ah,byte ptr Adresse + 1
  261.   out     dx,ax
  262.   mov     al,0Dh
  263.   mov     ah,byte ptr Adresse
  264.   out     dx,ax
  265. end;
  266.  
  267. begin
  268.   randomize;          { "Zufalls"zahlen generieren }
  269.   asm mov ax,13h; int 10h end;     { VGA-Modus 13h }
  270.   for i := 0 to 65535 do mem[vga:i] := random(256);
  271.   { Bildschirm füllen }
  272.   i := 0;
  273.   j := 80;
  274.   repeat
  275.     if keypressed then begin
  276.       c := readkey;
  277.       if c = ' ' then j := -j  { Richtung umkehren }
  278.       else exit;
  279.     end;
  280.     delay(10);             { Ohne Delay zu schnell }
  281.     waitretrace;
  282.     SetStart(i);        { Neue Startadresse setzen }
  283.     inc(i,j);          { Zähler erhöhen/vermindern }
  284.   until keypressed;
  285.   readkey;
  286.   asm mov ax,03h; int 10h end;        { Textmodus }
  287. end.
  288.  
  289. Die Prozedur SetStart bildet den Kern dieses Programms. Sie stellt mittels des
  290. CRTC ein, an welcher Adresse der Bilschirm 'beginnt'. Dabei wird kein einziges
  291. Byte kopiert oder bewegt, sondern bloß die Adresse, ab der die VGA die im
  292. Bildschirmspeicher abgelegten Informationen auf den Monitor bringt, verändert.
  293. Ruft man sie also mit
  294.  
  295. SetStart(32000);
  296.  
  297. auf, so wird der Bildschirminhalt erst ab dem Offset 32000 dargestellt. In
  298. diesem Modus gibt es aber wie gesagt den Nebeneffekt, daß hier in der zweiten
  299. Hälfte des Bildschirms der übersprungene Teil wieder angefügt wird. 
  300. Einen anderen Bereich der Scrollies, das Full-Screen-Scrolling, werden wir
  301. später behandeln, wenn wir zum Thema "Mode-X" kommen. Der Modus 13h hat nämlich
  302. das Manko, daß er nur eine Bildschirmseite unterstützt und so den Speicher der
  303. VGA-Karten (heutzutage mind. 512KB) kaum ausnutzt. Deshalb nützt das Scrolling
  304. des gesamten Bildschirminhalt mittels des CRTC (Cathode Ray Tube Controller)
  305. wenig, da immer nur derselbe Bildschirminhalt gescrollt werden kann. Im Mode-X
  306. (oder Chain-4) dagegen hat man bis zu 4 Virtuelle Bildschirme zur Verfügung.
  307. Aber das besprechen wir noch ausführlich in einem der nächsten Teile.
  308. Also, das war's zum Thema Scrollies, Thema von Part IV wahrscheinlich:
  309. Sprites.
  310.  
  311.  
  312.  
  313.  
  314.  
  315. [ This text copyright (c) 1995-96 Johannes Spohr. All rights reserved. ]
  316. [ Distributed exclusively through PC-Heimwerker, Verlag Thomas Eberle. ]
  317. [                                                                      ]
  318. [ No  part   of  this   document  may  be   reproduced,   transmitted, ]
  319. [ transcribed,  stored in a  retrieval system,  or translated into any ]
  320. [ human or computer language, in any form or by any means; electronic, ]
  321. [ mechanical,  magnetic,  optical,   chemical,  manual  or  otherwise, ]
  322. [ without the expressed written permission of the author.              ]
  323. [                                                                      ]
  324. [ The information  contained in this text  is believed  to be correct. ]
  325. [ The text is subject to change  without notice and does not represent ]
  326. [ a commitment on the part of the author.                              ]
  327. [ The author does not make a  warranty of any kind with regard to this ]
  328. [ material, including,  but not limited to,  the implied warranties of ]
  329. [ merchantability  and fitness  for a particular  purpose.  The author ]
  330. [ shall not be liable for errors contained herein or for incidental or ]
  331. [ consequential damages in connection with the furnishing, performance ]
  332. [ or use of this material.                                             ]
  333.